package view;

import java.rmi.RemoteException;

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;

import server.FirewallException;
import server.ReadWriteException;
import server.Rule;
import server.RulesTableType;

import controller.FirewallSession;

/**
 * Class is responsible for rules table.
 * Table is not editable, with specified header.
 * Resize of table is happened when received data take more than current lines number.
 */
public abstract class AbstractRulesTable extends JTable
{	
	/* Table data */
	public Rule[] rulesData;
	
	/* Table in/out type */
	private RulesTableType type = null;
	
	/*controlled object */
	public FirewallSession UI;
	public AbstractRulesTable(RulesTableType type, int height, int width, FirewallSession UI)
	{
		super(height, width);
	    setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		this.type = type;
		this.UI = UI;
		
	}

	/**
	 * Cancel cell editing for user.
	 */
	public boolean isCellEditable(int row, int column) 
	{
		return false;
	}
	
	/**
	 * Createa and returns table header.
	 * @return the header of the table
	 */
	public JTableHeader getRulesTableHeader()
	{
		String[] columnNames = getColumnsNames();
		
		TableColumn column = null;
		for (int i = 0; i < columnNames.length; i++)
		{
		    column = getColumnModel().getColumn(i);
		    column.setHeaderValue(columnNames[i]);
		}
		
		return getTableHeader();	
	}
	
	/**
	 * Returns the table columns names
	 * @return - the table columns names
	 */
	protected abstract String[] getColumnsNames();
	
	/**
	 * Take the data from FW.
	 */
	private void getRulesData() 
	{
		/* Current FW ruleset */
		try {
				
		/* IN or OUT rules */
			if(type.equals(RulesTableType.IN))
			{
				rulesData = UI.getRules(RulesTableType.IN, Settings.ruleset);
			}
			else
			{
				rulesData = UI.getRules(RulesTableType.OUT, Settings.ruleset);
			}
		} catch (RemoteException e) {
			ErrorFrame.AddError("Can't update rules tables :" + e.getMessage(), new JFrame());
		} catch (FirewallException e) {
			ErrorFrame.AddError("Can't update rules tables :" + e.getMessage(), new JFrame());
		}
	}

	/**
	 * Fill the rules table with data from FW.
	 */
	public void build()
	{
		getRulesData();
		
		if(rulesData == null || rulesData.length == 0)
		{
			/* Set the rules number */
			switch(type)
			{
			case IN:
				Settings.inRulesNumber = 0;
				break;
			case OUT:
				Settings.outRulesNumber = 0;
				break;
			}
			
			/* Clear the previous data */			
			((DefaultTableModel)getModel()).setRowCount(0);
			((DefaultTableModel)getModel()).setRowCount(Settings.DEFAULT_RULES_WINDOW_DEPTH);
			return;
		}
			
		/* Set the rules number */
		switch(type)
		{
		case IN:
			Settings.inRulesNumber = rulesData.length;
			break;
		case OUT:
			Settings.outRulesNumber = rulesData.length;
			break;
		}
			
		/* Add new rows if it's needed */
		int diff = rulesData.length - getModel().getRowCount();
		
		/* Clear the previous data */
		((DefaultTableModel)getModel()).setRowCount(0);
		if(diff > 0)
		{
			((DefaultTableModel)getModel()).setRowCount(rulesData.length);
		}
		else
		{
			((DefaultTableModel)getModel()).setRowCount(Settings.DEFAULT_RULES_WINDOW_DEPTH);
		}
		
		/* Fill the data */
		String str;
		for(int i = 0; i < rulesData.length; i++)
		{
			if ( rulesData[i] == null)
			{
					ErrorFrame.AddError("Bad data got from server: null pointer on index" + i, null);
					continue;
			}
			
			int j = 0;
			//index
			this.setValueAt(Integer.toString(rulesData[i].index), i, j++);
			
			//iprange
			this.setValueAt(rulesData[i].iprange,    i, j++);
			
			//port
			str = "";
			if(null != rulesData[i].port )
			{
				str  = Integer.toString(rulesData[i].port);
			}
			this.setValueAt(str,  i, j++);
			
			//protocol
			this.setValueAt(rulesData[i].protocol,   i, j++);
			
			//permissions
			str = "ALLOW";
			if(null != rulesData[i].permission )
			{
				str  = rulesData[i].permission.toString();
			}
			this.setValueAt(str, i, j++);
		}
	}
	
	/**
	 * Set ruleset from the table in FW.
	 */
	public void setRulesData()
	{
		/* Pass the data to the FW */
		try {
			UI.setRuleSet(Settings.ruleset);
		} catch (RemoteException e) {
			ErrorFrame.AddError("Failed to set ruleset as current:" + e.getMessage(), new JFrame());
		} catch (FirewallException e) {
			ErrorFrame.AddError("Failed to set ruleset as current:" + e.getMessage(), new JFrame());
		} catch (ReadWriteException e) {
			ErrorFrame.AddError("Failed to set ruleset as current:" + e.getMessage(), new JFrame());
		}
	}
	
	/**
	 * @return direction of rules in the table
	 */
	public String getType()
	{
		return type.toString();
	}
}
